/*! \file feature.h
	\author HiddenSeeker

	Describes a feature data name
*/
#include "list.h"
#include "identifierstring.h"
#include "renamenode.h"
#include "constant.h"
#include "entity.h"
#include <vector>
#include <map>
#include "../../semantics/argentry.h"
#pragma once


class FeatureDeclarationVisitor;

enum FeatureDeclarationType
{
	FDT_NONE=0,
	FDT_FROZEN=1,
	FDT_ABSTRACT=2,
	FDT_LIBRARY=4
};
/*! Compound is an expression list
*/
typedef ListNode<AbstractNode>  Compound;
/*! Defines a feature behaviour (method or field)
*/
class FeatureCommand
{
 public:
	    /*! Writes a behaviour to stream
			\param[in] decl    parent declaration
			\param[in] stream  stream
		*/
		virtual void  write(FeatureDeclaration * decl, GraphStream * stream)=0;
		/*! Fills attributes of classes
			\param[in] visitor visitor data
		 */
		virtual void fillAttribute(FeatureDeclarationVisitor * visitor)=0;
		/*! Destructor
		*/
		virtual ~FeatureCommand();
};
/*! Describes a deferred method behaviour
*/
class DeferredMethodDeclaration: public FeatureCommand
{
 public:
	      void  write(FeatureDeclaration * decl, GraphStream * stream);
		  /*! Fills attributes of classes
			\param[in] visitor visitor data
		  */
		  virtual void fillAttribute(FeatureDeclarationVisitor * visitor);
};
/*! Describes a field behaviour
*/
class FieldDeclaration: public FeatureCommand
{
 public:
	      void  write(FeatureDeclaration * decl, GraphStream * stream);
		  /*! Fills attributes of classes
			\param[in] visitor visitor data
		  */
		   virtual void fillAttribute(FeatureDeclarationVisitor * visitor);
};
class MethodDeclaration: public FeatureCommand
{
 public:
	      void  write(FeatureDeclaration * decl, GraphStream * stream);
		  /*! Fills attributes of classes
			\param[in] visitor visitor data
		  */
		  virtual void fillAttribute(FeatureDeclarationVisitor * visitor);
};

class FeatureSpecName: public AbstractNode
{
 private:
	      FeatureDeclarationType m_spec;
		  std::string *          m_name;
		  std::string *          m_alias;
 public:
	 inline FeatureDeclarationType spec() const { return m_spec;    }
	 inline const std::string &    name() const { return *m_name;   }
	 inline const std::string *    alias() const { return  m_alias;}
	 /*! Constructor
	 */
	 inline FeatureSpecName(const YYLTYPE & pos, FeatureDeclarationType spec, std::string * name,std::string * alias): AbstractNode(pos)
	 {
		 m_spec=spec;
		 m_name=name;
		 m_alias=alias;
	 }
	 /*! Writes a declaration to stream
		 \param[in] s stream
	  */
	 void  write(GraphStream * s);
     /*! Destructor
	 */
	 ~FeatureSpecName();
};

std::string getNamesList(ListNode<FeatureSpecName> * specnames);
/*! Adds an element to list
	\param[in] specnames list of specs
	\param[in] pos       position
	\param[in] fdt       declaration
	\param[in] str       string
*/
inline ListNode<FeatureSpecName> * add(ListNode<FeatureSpecName> * specnames,
									   const YYLTYPE & pos, 
									   FeatureDeclarationType fdt, 
									   std::string * str, std::string * alias)
{
	specnames->add(new FeatureSpecName(pos,fdt,str,alias));
	return specnames;
}
/*! Describes a feature declaration
*/
class FeatureDeclaration: public AbstractNode
{
  friend class  DeferredMethodDeclaration;
  friend class  FieldDeclaration;
  friend class  MethodDeclaration;

  private:
	       /*! List of specified names
 		   */
	       ListNode<FeatureSpecName> * m_specnames;
		   /*! Behaviour of the feature
		   */
		   FeatureCommand *           m_behaviour;
		   /*! Formal argument
		   */
		   EntityList  *   m_formal_args;
		   /*! Return type (or variable type)
		   */
		   ClassTypeNode * m_return_type;
		   /*! Local variables
		   */
		   EntityList *    m_local_vars;
		   /*! Routine
		   */
		   Compound   *    m_routine;
		   
		   /*! Returns a common name of feature declaration
		   */
		   std::string getNamesList();
		   /*! Writes a node to stream, binding an edge to it
			   \param[in] node  node
			   \param[in] mark label of edge
			   \param[out] stream changing stream
		   */
		   void  write(AbstractNode * node,const std::string & mark,GraphStream * s);

		   std::vector<ArgEntry>  m_formal_list;
		   std::vector<ArgEntry>  m_local_list;
		   FeatureDeclarationType  m_decltype;
		   std::string m_curname;
		   const std::string * m_curalias;
		   FeatureSpecName *   m_curspec;
  public:
	  inline const std::vector<ArgEntry>& formalList() const { return m_formal_list;}
	  inline const std::vector<ArgEntry> & localList() const { return m_local_list;}
	  inline FeatureDeclarationType  declType() const { return m_decltype;}
	  inline ClassTypeNode * returnType() const {return m_return_type; }
	  inline Compound *      compound() const {return m_routine; }
	  inline const std::string & currentName() const {return m_curname;}
	  inline const std::string * currentAlias() const { return m_curalias; }
	  inline FeatureSpecName  * currentSpec() const {return m_curspec;}


	  inline EntityList * formalArgs() const { return m_formal_args; }
	  inline EntityList * localVars() const  { return m_local_vars;  }
	  inline Compound   * routine()  const  { return m_routine; }
	  inline ListNode<FeatureSpecName> * specNames() const  { return m_specnames; }
	  /*! Fills attributes of classes
		   \param[in] visitor visitor data
	   */
	  void fillAttribute(FeatureDeclarationVisitor * visitor);
	  inline FeatureDeclaration(const YYLTYPE & pos): AbstractNode(pos)
	  {
		  m_behaviour=NULL;
		  m_formal_args=NULL;
		  m_return_type=NULL;
		  m_local_vars=NULL;
		  m_specnames=NULL;
		  m_routine=NULL;
	  }
	  /*! Creates a 
		  \param[in] pos   position
		  \param[in] names names
		  \param[in] type  return type
	  */
	  inline FeatureDeclaration(const YYLTYPE & pos,
		                        ListNode<FeatureSpecName> * names,
								ClassTypeNode * type): AbstractNode(pos)
	  {
		  m_behaviour=new FieldDeclaration();
		  m_formal_args=NULL;
		  m_return_type=type;
		  m_local_vars=NULL;
		  m_specnames=names;
		  m_routine=NULL;
	  }
	  
	  /*! Creates a deferred method
		  \param[in] pos        position
		  \param[in] names      names of data
		  \param[in] formalargs formal arguments
		  \param[in] type       type arguments
	  */
	  FeatureDeclaration(const YYLTYPE & pos,ListNode<FeatureSpecName> * names,
		                EntityList * formalargs,ClassTypeNode * type);
	  /*! Creates a fully-functional method
		  \param[in] pos        position
		  \param[in] names      names of data
		  \param[in] formalargs formal arguments
		  \param[in] type       type arguments
		  \param[in] localvars  localvariables
		  \param[in] routine    routine
	  */
	  FeatureDeclaration(const YYLTYPE & pos,ListNode<FeatureSpecName> * names,
		                EntityList * formalargs,ClassTypeNode * type,
						EntityList * localvars,Compound * routine);	  
	  /*! Writes a declaration to stream
	  */
	  void  write(GraphStream * s);
	  /*! Makes feature declaration returning constant
	  */
	  void setExplicitValue(AbstractNode * explicitvalue);
	  /*! Transforms it to deferred method
	  */
	  void makeDeferredMethod();
	  /*! Transforms it to effective method
		  \param[in] local   local variables
		  \param[in] routine routine data
	  */
	  void makeEffective(EntityList * local,Compound * routine);
	  /*! Destructor
	  */
	  ~FeatureDeclaration();
};

/*! Describes a feature group
*/
class FeatureGroup: public AbstractNode
{
 private:
	     ListNode<IdentifierNode> * m_clients;
		 ListNode<FeatureDeclaration> * m_features;
public:
	    inline ListNode<IdentifierNode> * clients() const { return m_clients; }
		inline ListNode<FeatureDeclaration> * features() const { return m_features; }
		inline FeatureGroup(const YYLTYPE & pos,
			         ListNode<IdentifierNode> * clients,
					 ListNode<FeatureDeclaration> * features): AbstractNode(pos)
		{
			m_clients=clients;
			m_features=features;
		}
		/*! Fills attributes of classes
		   \param[in] visitor visitor data
	    */
	    void fillAttribute(FeatureDeclarationVisitor * visitor);
		/*! Writes a declaration to stream
	     */
	    void  write(GraphStream * s);
		inline ~FeatureGroup()
		{
			if (this->isOwningData())
			{
				delete m_clients;
				delete m_features;
			}
		}
};


Compound * createExplicitValueRoutine(AbstractNode * node);
